import {
	ICodeListItem,
	ICodeListResult,
	IContext,
	IHttpResponse,
	IParam,
	ITreeNodeModel,
	ITreeNodeRsModel,
} from '@/core/interface';
import { deepCopy, HttpResponse, isEmpty } from '@/core/utils';
import { ControlVOBase } from '../control-vo';
import { CtrlExServiceBase } from './ctrl-ex-service-base';

/**
 * 树部件服务
 *
 * @class TreeService
 */
class TreeService<T extends ControlVOBase[]> extends CtrlExServiceBase<T> {
	/**
	 * 节点分隔符
	 *
	 * @private
	 * @type {string}
	 * @memberof TreeService
	 */
	private TREENODE_SEPARATOR = ';';

	/**
	 * Creates an instance of TreeService.
	 * @param {IParam[]} controlVOTypes
	 * @param {string} entityCodeName
	 * @param {IParam} [opts]
	 * @memberof TreeService
	 */
	constructor(controlVOTypes: IParam[], entityCodeName: string, opts?: IParam) {
		super(controlVOTypes, entityCodeName, opts);
		this.model = opts!.model;
	}

	/**
	 * 获取节点数据
	 *
	 * @param {IContext} context
	 * @param {IParam} data
	 * @return {*}
	 * @memberof TreeService
	 */
	async getNodes(context: IContext, data: IParam): Promise<IHttpResponse<any>> {
		let { srfparentkey, srfcat, srfnodeid, srfnodefilter, query } = data;
		srfnodefilter = query ? query : srfnodefilter;
		const list: any[] = [];
		const filter: any = {};
		const { treeNodes, rootVisible } = this.model;
		//  根节点
		const rootNode = treeNodes.find((node: ITreeNodeModel) => {
			return node.rootNode;
		}) as ITreeNodeModel;
		if (!srfnodeid || Object.is(srfnodeid, '#')) {
			if (rootVisible) {
				// 处理是否显示根节点
				srfnodeid = rootNode.nodeType;
				// await this.fillNodeData(rootNode, context, filter, list);
				// return new HttpResponse(list);
			} else {
				srfnodeid = rootNode.nodeType;
			}
		}
		const strTreeNodeId: string = srfnodeid;
		let strRealNodeId = '';
		const bRootSelect = false;
		let strNodeType: string;
		const strRootSelectNode = '';
		if (Object.is(strTreeNodeId, rootNode.nodeType)) {
			strNodeType = rootNode.nodeType;
			if (srfparentkey) {
				strRealNodeId = srfparentkey;
			}
		} else {
			const nPos = strTreeNodeId.indexOf(this.TREENODE_SEPARATOR);
			if (nPos === -1) {
				return Promise.reject({
					status: 500,
					data: { title: '失败', message: `树节点${strTreeNodeId}标识无效` },
				});
			}
			strNodeType = strTreeNodeId.substring(0, nPos);
			strRealNodeId = strTreeNodeId.substring(nPos + 1);
		}

		// 处理过滤参数
		Object.assign(filter, {
			srfparentkey: srfparentkey,
			srfcat: srfcat,
			srfnodefilter: srfnodefilter,
			strRealNodeId: strRealNodeId,
			srfnodeid: srfnodeid,
			strNodeType: strNodeType,
			viewParams: deepCopy(data).viewParams,
			srfparentdata: deepCopy(data).parentData,
		});

		// 分解节点标识
		const nodeid: string[] = strRealNodeId.split(this.TREENODE_SEPARATOR);
		for (let i = 0; i < nodeid.length; i++) {
			switch (i) {
				case 0:
					Object.assign(filter, { nodeid: nodeid[0] });
					break;
				case 1:
					Object.assign(filter, { nodeid2: nodeid[1] });
					break;
				case 2:
					Object.assign(filter, { nodeid3: nodeid[2] });
					break;
				case 3:
					Object.assign(filter, { nodeid4: nodeid[3] });
					break;
				default:
					break;
			}
		}

		// 根据节点标识填充节点
		const node = treeNodes.find((_node: ITreeNodeModel) => {
			return _node.nodeType == strNodeType;
		});
		if (node) {
			await this.fillChildNodes(node, context, filter, list);
			return new HttpResponse(list);
		} else {
			return new HttpResponse(
				{ title: '失败', message: `树节点${strTreeNodeId}标识无效` },
				null,
				500
			);
		}
	}

	/**
	 * 根据节点关系填充所有子节点
	 *
	 * @private
	 * @param {ITreeNodeModel} node
	 * @param {*} [context={}]
	 * @param {*} filter
	 * @param {any[]} list
	 * @return {*}  {Promise<any>}
	 * @memberof TreeService
	 */
	private async fillChildNodes(
		node: ITreeNodeModel,
		context: any = {},
		filter: any,
		list: any[]
	): Promise<any> {
		// 过滤出父节点是该节点的节点关系集合
		const { treeNodes, treeNodeRSs } = this.model;
		if (treeNodeRSs.length > 0) {
			const nodeRSs = treeNodeRSs.filter((nodeRS: ITreeNodeRsModel) => {
				if (nodeRS.parentPSDETreeNodeId !== node.id) {
					return false;
				}
				// 搜索模式 1 有搜索时启用， 2 无搜索时启用， 3 全部启用
				switch (nodeRS.searchMode) {
					case 1:
						return !isEmpty(filter.srfnodefilter);
					case 2:
						return isEmpty(filter.srfnodefilter);
					case 3:
						return true;
					default:
						return false;
				}
			});
			// 填充对应节点关系的子节点
			if (nodeRSs && nodeRSs.length > 0) {
				for (let i = 0, len = nodeRSs.length; i < len; i++) {
					const rsNavContext: any = nodeRSs[i].navigateContext;
					const rsNavParams: any = nodeRSs[i].navigateParams;
					const rsParams: any = nodeRSs[i].params;
					// 根据节点标识填充节点
					const treeNode: any = treeNodes.find((_node: ITreeNodeModel) => {
						return nodeRSs[i].childDeTreeNodeId == _node.id;
					});
					if (treeNode) {
						await this.fillNodeData(
							treeNode,
							context,
							filter,
							list,
							rsNavContext,
							rsNavParams,
							rsParams
						);
					}
				}
			}
		}
	}

	/**
	 * 填充节点数据
	 *
	 * @private
	 * @param {ITreeNodeModel} node
	 * @param {IContext} context
	 * @param {*} filter
	 * @param {IParam[]} list
	 * @param {IParam} [rsNavContext]
	 * @param {IParam} [rsNavParams]
	 * @param {IParam} [rsParams]
	 * @return {*}  {Promise<any>}
	 * @memberof TreeService
	 */
	private fillNodeData(
		node: ITreeNodeModel,
		context: IContext,
		filter: any,
		list: IParam[],
		rsNavContext?: IParam,
		rsNavParams?: IParam,
		rsParams?: IParam
	): Promise<any> {
		context = this.handleResNavContext(context, filter, rsNavContext);
		filter = this.handleResNavParams(context, filter, rsNavParams, rsParams);
		return new Promise((resolve: any, reject: any) => {
			//  静态节点
			if (node.treeNodeType == 'STATIC') {
				//  快速搜索过滤
				if (
					node.enableQuickSearch &&
					filter.srfnodefilter &&
					!Object.is(filter.srfnodefilter, '') &&
					node.text
						?.toUpperCase()
						.indexOf(filter.srfnodefilter.toUpperCase()) == -1
				) {
					resolve(list);
					return;
				}
				const treeNode: any = {
					allowDrag: node.allowDrag,
					allowDrop: node.allowDrop,
					allowEditText: node.allowEditText,
					allowOrder: node.allowOrder,
					appendCaption: node.appendCaption,
					counterId: node.counterId,
					class: node.cssName,
					text: App.ts(node.lanResTag as string, node.text),
					textFormat: node.textFormat,
					tooltip: App.ts(node.tooltipLanResTag as string, node.tooltip),
					nodeType: node.nodeType,
					srfappctx: context,
					srfmajortext: node.text,
					enableCheck: node.enableCheck,
					disabled: node.disableSelect,
					expanded: node.expanded || filter.isAutoExpand,
					isLeaf: node.leaf,
					selected: node.selected,
					navFilter: node.navFilter,
					cssClass: node.cssClass,
					imagePath: node.imagePath,
					counterMode: node.counterMode,
					contextMenus: node.contextMenus,
				};
				!treeNode.isLeaf ? (treeNode.children = []) : null;
				//  删除无用属性
				let strNodeId: string = node.nodeType;
				if (isEmpty(node.nodeValue)) {
					Object.assign(treeNode, { srfkey: node.nodeValue });
					strNodeId += this.TREENODE_SEPARATOR + node.nodeValue;
					if (node.appendPNodeId) {
						strNodeId += this.TREENODE_SEPARATOR + filter.strRealNodeId;
					}
				} else {
					//  没有指定节点值，直接使用父节点值
					Object.assign(treeNode, { srfkey: filter.strRealNodeId });
					strNodeId += this.TREENODE_SEPARATOR + filter.strRealNodeId;
				}
				Object.assign(treeNode, { id: strNodeId });
				Object.assign(treeNode, {
					nodeid: treeNode.srfkey,
					nodeid2: filter.strRealNodeId,
				});
				list.push(treeNode);
				resolve(list);
			} else if (node.treeNodeType == 'CODELIST') {
				//  代码表节点
				if (node.codeListTag) {
					App.getAppCodeListHelper()
						.getCodeListItems(node.codeListTag, context)
						.then((codeListResult: ICodeListResult) => {
							if (codeListResult.ok) {
								const treeNodes: any[] = this.transFormCodeListData(
									codeListResult.data,
									context,
									filter,
									node
								);
								list.push(...treeNodes);
								resolve(list);
							}
							resolve([]);
						})
						.catch(() => {
							resolve([]);
						});
				} else {
					resolve([]);
				}
			} else if (node.treeNodeType == 'DE' && node.entityCodeName) {
				//  实体节点
				let bFirst = true;
				const searchFilter: any = {};
				const { treeNodeRSs, treeNodes } = this.model;
				if (treeNodeRSs && treeNodeRSs.length > 0) {
					treeNodeRSs.forEach((nodeRs: ITreeNodeRsModel) => {
						if (nodeRs.childDeTreeNodeId == node.id) {
							const pickupField: string = nodeRs.parentFilter
								? nodeRs.parentFilter.toLowerCase()
								: nodeRs.parentPSDER1N && nodeRs.parentPSAppDEField
								? nodeRs.parentPSAppDEField.toLowerCase()
								: '';
							if (pickupField && pickupField !== '') {
								const tempNode = treeNodes.find((_node: ITreeNodeModel) => {
									return nodeRs.parentPSDETreeNodeId == _node.id;
								});
								if (
									tempNode &&
									Object.is(filter.strNodeType, tempNode.nodeType)
								) {
									Object.assign(searchFilter, {
										[`n_${pickupField}_eq`]:
											filter[
												`nodeid${
													nodeRs.parentValueLevel > 1
														? nodeRs.parentValueLevel
														: ''
												}`
											],
									});
								}
							}
						}
					});
				}
				Object.assign(searchFilter, { total: false });
				if (node.enableQuickSearch) {
					Object.assign(searchFilter, { query: filter.srfnodefilter });
				}
				try {
					this.searchNodeData(node, context, searchFilter, filter).then(
						(records: any) => {
							if (records && records.length) {
								records.forEach((entity: any) => {
									const treeNode: any = {
										appendCaption: node.appendCaption,
										appEntityCodeName: node.entityCodeName,
										allowDrag: node.allowDrag,
										allowDrop: node.allowDrop,
										allowEditText: node.allowEditText,
										allowOrder: node.allowOrder,
										curData: entity,
										counterId: node.counterId,
										class: node.cssName,
										counterMode: node.counterMode,
										disabled: node.disableSelect,
										enableCheck: node.enableCheck,
										expanded: node.expanded
											? node.expandFirstOnly
												? bFirst
												: true
											: filter.isAutoExpand,
										textFormat: node.textFormat,
										selected: node.selected,
										isLeaf: node.leaf,
										navFilter: node.navFilter,
										nodeType: node.nodeType,
										contextMenus: node.contextMenus,
									};
									!treeNode.isLeaf ? (treeNode.children = []) : null;
									const strId: string = entity.id
										? entity.id
										: entity[(node.keyPSAppDEField as string).toLowerCase()];
									const strText: string = entity.text
										? entity.text
										: entity[(node.majorPSAppDEField as string).toLowerCase()];
									Object.assign(treeNode, {
										srfparentdename: node.entityCodeName?.toLowerCase(),
										srfparentdemapname: node.entityCodeName,
										srfparentkey: strId,
									});
									const tempContext = deepCopy(context);
									Object.assign(tempContext, {
										srfparentdename: node.entityCodeName?.toLowerCase(),
										srfparentdemapname: node.entityCodeName,
										srfparentkey: strId,
										[(node.entityCodeName as string).toLowerCase()]: strId,
									});
									Object.assign(treeNode, {
										srfappctx: tempContext,
										[(node.entityCodeName as string).toLowerCase()]: strId,
										srfkey: strId,
										text: strText,
										srfmajortext: strText,
									});
									let strNodeId: string = node.nodeType;
									strNodeId += this.TREENODE_SEPARATOR + strId;
									if (node.appendPNodeId) {
										strNodeId += this.TREENODE_SEPARATOR + filter.realnodeid;
									}
									Object.assign(treeNode, { id: strNodeId });
									if (entity.icon) {
										Object.assign(treeNode, { imagePath: entity.icon });
									} else {
										Object.assign(treeNode, {
											cssClass: node.cssClass,
											imagePath: node.imagePath,
										});
									}
									if (entity.leafflag) {
										const strLeafFlag: string = entity.leafflag
											.toString()
											.toLowerCase();
										if (
											Object.is(strLeafFlag, '1') ||
											Object.is(strLeafFlag, 'true')
										) {
											Object.assign(treeNode, { isLeaf: true });
										} else {
											Object.assign(treeNode, {
												isLeaf: false,
												children: treeNode.children || [],
											});
										}
									}
									const nodeDataItems: any[] = node.deTreeNodeDataItems || [];
									if (nodeDataItems.length > 0) {
										nodeDataItems.forEach((item: any) => {
											const name = item.name.toLowerCase();
											if (item.fieldCodeName) {
												Object.assign(treeNode, {
													[name]: entity[item.fieldCodeName.toLowerCase()],
												});
											}
											if (Object.is('text', name) && item.customCode) {
												Object.assign(treeNode, {
													textCustomCode: true,
													textScriptCode: item.scriptCode,
												});
											}
											if (Object.is('icon', name) && item.customCode) {
												Object.assign(treeNode, {
													iconCustomCode: true,
													iconScriptCode: item.scriptCode,
												});
											}
										});
									}
									if (entity.counterid) {
										Object.assign(treeNode, { counterId: entity.counterid });
									}
									Object.assign(treeNode, {
										nodeid: treeNode.srfkey,
										nodeid2: filter.strRealNodeId,
									});
									list.push(treeNode);
									resolve(list);
									bFirst = false;
								});
							} else {
								resolve(list);
							}
						}
					);
				} catch (error: any) {
					console.error(error);
				}
			} else {
				resolve(list);
			}
		});
	}

	/**
	 * 转换代码表数据为树节点数据
	 *
	 * @private
	 * @param {ICodeListItem[]} codeItems
	 * @param {*} context
	 * @param {*} filter
	 * @param {ITreeNodeModel} node
	 * @return {*}  {any[]}
	 * @memberof TreeService
	 */
	private transFormCodeListData(
		codeItems: ICodeListItem[],
		context: any,
		filter: any,
		node: ITreeNodeModel
	): any[] {
		const treeNodes: any[] = [];
		let bFirst = true;
		if (codeItems.length) {
			for (const item of codeItems) {
				const treeNode: any = {
					srfappctx: context,
					srfmajortext: item.text,
					curData: item,
					text: item.text,
					srfkey: item.value,
					nodeType: node.nodeType,
					appendCaption: node.appendCaption,
					allowDrag: node.allowDrag,
					allowDrog: node.allowDrop,
					allowEditText: node.allowEditText,
					allowOrder: node.allowOrder,
					class: node.cssName,
					counterId: node.counterId,
					counterMode: node.counterMode,
					disabled: node.disableSelect,
					enableCheck: node.enableCheck,
					expanded: node.expanded
						? node.expandFirstOnly
							? bFirst
							: true
						: filter.isAutoExpand,
					cssClass: node.cssClass,
					imagePath: node.imagePath,
					selected: node.selected,
					navFilter: node.navFilter,
					nodeid: item.value,
					nodeid2: filter.strRealNodeId,
				};
				//  快速搜索过滤
				if (node.enableQuickSearch && filter.srfnodefilter) {
					const pattern = new RegExp(`${node.text}`, 'i');
					if (filter.srfnodefilter.search(pattern) === -1) {
						continue;
					}
				}
				let strNodeId = `${node.nodeType}${this.TREENODE_SEPARATOR}${item.value}`;
				if (node.appendPNodeId) {
					strNodeId += `${this.TREENODE_SEPARATOR}${filter.realnodeid}`;
				}
				Object.assign(treeNode, { id: strNodeId });

				if ((item as any).items?.length > 0) {
					const children = this.transFormCodeListData(
						(item as any).items,
						context,
						filter,
						node
					);
					Object.assign(treeNode, { isLeaf: false, children: children });
				} else {
					Object.assign(treeNode, { isLeaf: true });
				}
				treeNodes.push(treeNode);
			}
		}
		bFirst = false;
		return treeNodes;
	}

	/**
	 * 查询节点数据
	 *
	 * @private
	 * @param {ITreeNodeModel} node
	 * @param {IContext} context
	 * @param {*} searchFilter
	 * @param {*} filter
	 * @return {*}  {Promise<any>}
	 * @memberof TreeService
	 */
	private async searchNodeData(
		node: ITreeNodeModel,
		context: IContext,
		searchFilter: any,
		filter: any
	): Promise<any> {
		if (filter.viewParams) {
			Object.assign(searchFilter, filter.viewParams);
		}
		if (!searchFilter.page) {
			Object.assign(searchFilter, { page: 0 });
		}
		if (!searchFilter.size) {
			Object.assign(searchFilter, { size: 1000 });
		}
		if (context && context.srfparentdename) {
			Object.assign(searchFilter, { srfparentdename: context.srfparentdename });
		}
		if (context && context.srfparentkey) {
			Object.assign(searchFilter, { srfparentkey: context.srfparentkey });
		}
		if (node.sortPSAppDEField) {
			Object.assign(searchFilter, {
				sort: `${node.sortPSAppDEField.toLowerCase()},${
					node.sortDir ? node.sortDir : 'asc'
				}`,
			});
		}
		const result: any = [];
		if (node.entityCodeName && node.appDeDataSet) {
			const appEntityService = await App.getDataService(
				node.entityCodeName,
				context
			);
			if (
				appEntityService &&
				appEntityService[node.appDeDataSet] instanceof Function
			) {
				try {
					const response: IHttpResponse = await appEntityService[
						node.appDeDataSet
					](context, searchFilter, false);
					if (response.success) {
						if (response.data instanceof Array) {
							response.data.forEach((item: any, index: number) => {
								result.push(this.newControlVO(item, `${node.controlVoName}`));
							});
						} else {
							result.push(
								this.newControlVO(response.data, `${node.controlVoName}`)
							);
						}
					}
					return result;
				} catch (error) {
					return result;
				}
			}
		} else {
			return result;
		}
	}

	/**
	 * 处理关系导航上下文
	 *
	 * @private
	 * @param {*} context
	 * @param {*} filter
	 * @param {*} resNavContext
	 * @return {*}
	 * @memberof TreeService
	 */
	private handleResNavContext(context: any, filter: any, resNavContext: any) {
		if (resNavContext && Object.keys(resNavContext).length > 0) {
			const tempContextData: any = deepCopy(context);
			let tempViewParams: any = {};
			if (filter && filter.viewparams) {
				tempViewParams = filter.viewparams;
			}
			Object.keys(resNavContext).forEach((item: any) => {
				const curDataObj: any = resNavContext[item];
				this.handleCustomDataLogic(
					context,
					tempViewParams,
					curDataObj,
					tempContextData,
					item,
					filter?.srfparentdata
				);
			});
			return tempContextData;
		} else {
			return context;
		}
	}

	/**
	 * 处理关系导航参数
	 *
	 * @private
	 * @param {*} context
	 * @param {*} filter
	 * @param {*} resNavParams
	 * @param {*} resParams
	 * @return {*}
	 * @memberof TreeService
	 */
	private handleResNavParams(
		context: any,
		filter: any,
		resNavParams: any,
		resParams: any
	) {
		if (
			(resNavParams && Object.keys(resNavParams).length > 0) ||
			(resParams && Object.keys(resParams).length > 0)
		) {
			let tempViewParamData: any = {};
			let tempViewParams: any = {};
			if (filter && filter.viewParams) {
				tempViewParams = filter.viewParams;
				tempViewParamData = deepCopy(filter.viewParams);
			}
			if (resNavParams && Object.keys(resNavParams).length > 0) {
				Object.keys(resNavParams).forEach((item: any) => {
					const curDataObj: any = resNavParams[item];
					this.handleCustomDataLogic(
						context,
						tempViewParams,
						curDataObj,
						tempViewParamData,
						item,
						filter?.srfparentdata
					);
				});
			}
			if (resParams && Object.keys(resParams).length > 0) {
				Object.keys(resParams).forEach((item: any) => {
					const curDataObj: any = resParams[item];
					tempViewParamData[item.toLowerCase()] = curDataObj;
				});
			}
			Object.assign(filter, { viewParams: tempViewParamData });
			return filter;
		} else {
			return filter;
		}
	}

	/**
	 * 处理自定义节点关系导航数据
	 *
	 * @private
	 * @param {*} context
	 * @param {*} viewParams
	 * @param {*} curNavData
	 * @param {*} tempData
	 * @param {string} item
	 * @param {*} [parentData]
	 * @memberof TreeService
	 */
	private handleCustomDataLogic(
		context: any,
		viewParams: any,
		curNavData: any,
		tempData: any,
		item: string,
		parentData?: any
	) {
		if (curNavData && curNavData.startsWith('%') && curNavData.endsWith('%')) {
			const param = curNavData.slice(1, curNavData.length - 1)?.toLowerCase();
			// 先从导航上下文取数，没有再从导航参数（URL）取数，如果导航上下文和导航参数都没有则为null
			if (parentData && param && parentData[param] != null) {
				Object.defineProperty(tempData, item.toLowerCase(), {
					value: parentData[param],
					writable: true,
					enumerable: true,
					configurable: true,
				});
			} else if (context[param] != null) {
				Object.defineProperty(tempData, item.toLowerCase(), {
					value: context[param],
					writable: true,
					enumerable: true,
					configurable: true,
				});
			} else {
				if (viewParams[param] != null) {
					Object.defineProperty(tempData, item.toLowerCase(), {
						value: viewParams[param],
						writable: true,
						enumerable: true,
						configurable: true,
					});
				} else {
					Object.defineProperty(tempData, item.toLowerCase(), {
						value: null,
						writable: true,
						enumerable: true,
						configurable: true,
					});
				}
			}
		} else {
			//  直接值
			if (isEmpty(curNavData.value)) {
				Object.defineProperty(tempData, item.toLowerCase(), {
					value: null,
					writable: true,
					enumerable: true,
					configurable: true,
				});
			} else {
				Object.defineProperty(tempData, item.toLowerCase(), {
					value: curNavData.value,
					writable: true,
					enumerable: true,
					configurable: true,
				});
			}
		}
	}
}
export default TreeService;
